package tree;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.Random;

import javax.swing.text.html.HTMLDocument.Iterator;

/**
 * A testbench for doing analysis on a binary tree
 * 
 * @author Axel Sundbom, Johannes Sjölund, Tim Danielsson
 * 
 */
public class TestBench {
	private OutputStream outputStream = System.out;
	private OutputStreamWriter outputWriter;

	private void setOutput(OutputStream target) {
		this.outputStream = target;
		outputWriter = new OutputStreamWriter(target);
	}

	public TestBench() {
		setOutput(System.out);
	}

	public TestBench(OutputStream specialOut) {
		setOutput(specialOut);
	}

	/**
	 * Print output to our stream
	 * 
	 * @param in
	 *            the text to print
	 */
	private void printStream(String in) {
		try {
			outputWriter.write(in);
			outputWriter.flush();
		} catch (IOException e) {
			System.err.println(e);
		}
	}

	/**
	 * Insert a word into the tree, then lookup that word. Measure number of
	 * operations in string comparison method.
	 */
	public void testLookupComplexityOnWordLength() {
		int treeSize = 1;
		int minWordLength = 1;
		int maxWordLength = 1000;

		for (int wordLength = minWordLength; wordLength <= maxWordLength; wordLength++) {

			BinaryTree bt = new BinaryTree();

			bt.resetCounters();

			RandomWordFactory words = new RandomWordFactory(treeSize,
					wordLength, wordLength);

			words.initializeRandoms();
			String key = words.nextRandom();

			bt.insert(key, "test");
			bt.lookup(key);

			printStream(BinaryTree.compareOperations + "," + wordLength
					+ "\r\n");

		}
	}

	/**
	 * Runs a complexity test to see how lookup time grows as tree gets larger.
	 * Insert random words into the tree then run lookup for one of them. Runs
	 * several randomized samples, then measures the average number of
	 * operations.
	 */
	public void testLookupComplexity() {

		int minWordLength = 5;
		int maxWordLength = 25;
		int numberOfRandoms = 1000;
		int samples = 10;
		int n = 1000;
		int[] result = new int[n];

		Random r = new Random();
		RandomWordFactory randoms = new RandomWordFactory(numberOfRandoms,
				minWordLength, maxWordLength);
		BinaryTree bt = new BinaryTree();

		ArrayList<String> added = new ArrayList<String>();

		for (int j = 0; j < samples; j++) {
			bt.resetTree();
			randoms.initializeRandoms();

			for (int i = 0; i < n; i++) {

				String word = randoms.nextRandom();
				added.add(word);
				bt.insert(word, word);

				bt.resetCounters(); // reset counters
				String lookupWord = added.get(r.nextInt(added.size()));
				bt.lookupNode(lookupWord);

				result[i] += bt.lookupOperations + bt.compareOperations;
			}
		}

		for (int i = 0; i < n; i++) {
			printStream(result[i] / samples + "," + i + "\r\n");
		}

	}

	/**
	 * Runs a complexity test to see how lookup time grows as tree gets BIG.
	 * Insert random words into the tree then run lookup for one of them. Runs
	 * several randomized samples, then measures the average number of
	 * operations.
	 */
	public void testLookupComplexityBigNumbers() {

		int minWordLength = 5;
		int maxWordLength = 25;
		int numberOfRandoms = 5000;
		int samples = 1;
		int n = 100;
		int interval = 1;
		int[] result = new int[n / interval];

		Random r = new Random();
		RandomWordFactory randoms = new RandomWordFactory(n, minWordLength,
				maxWordLength);
		BinaryTree bt = new BinaryTree();

		ArrayList<String> added = new ArrayList<String>();

		for (int j = 0; j < samples; j++) {
			bt.resetTree();
			randoms.initializeRandoms();

			for (int i = 0; i < n; i += interval) {

				for (int k = 0; k < interval; k++) {
					String word = randoms.nextRandom();
					added.add(word);
					bt.insert(word, word);
				}
				System.out.println(interval);

				bt.resetCounters(); // reset counters
				String lookupWord = added.get(r.nextInt(added.size()));
				bt.lookupNode(lookupWord);
				result[i / interval] += bt.lookupOperations
						+ bt.compareOperations;
			}
		}

		for (int i = 0; i < n; i += interval) {
			printStream(result[i / interval] / samples + "," + i + "\r\n");
		}

	}

	/**
	 * Runs a complexity test to see how insert time grows as tree gets larger.
	 * Insert random words into the tree. Runs several randomized samples, then
	 * measures the average number of operations.
	 */
	public void testInsertionComplexity() {

		int minWordLength = 5;
		int maxWordLength = 25;
		int numberOfRandoms = 1000;
		int samples = 1;
		int n = 100;
		int[] result = new int[n];

		RandomWordFactory randoms = new RandomWordFactory(numberOfRandoms,
				minWordLength, maxWordLength);
		BinaryTree bt = new BinaryTree();

		for (int j = 0; j < samples; j++) {
			bt.resetTree();
			randoms.initializeRandoms();

			for (int i = 0; i < n; i++) {

				bt.resetCounters(); // reset counters
				String word = randoms.nextRandom(); // pop next random "word"
				bt.insert(word, word);

				result[i] += bt.insertOperations + bt.rotateOperations
						+ bt.compareOperations;
			}
		}

		for (int i = 0; i < n; i++) {
			System.out.println(result[i] / samples + "," + i);
		}
	}

	public void regularTest(BinaryTree bt) {
		bt.insert("katt", "cat");
		bt.insert("katt", "kitty");
		bt.insert("hund", "dog");
		bt.insert("fluga", "fly");
		bt.insert("groda", "frog");
		bt.insert("groda", "toad");
		bt.insert("grodan smaskade i sig flugan", "the frog gobbeled up the fly");
		bt.insert("pingvin", "penguin");
		bt.insert("pengvin", "kassako");
		bt.insert("skalbagge", "beetle");
		bt.insert("troglodyt", "troglodyte");
	}

}
